package model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Game {
	private IDeck deck;
	private List<Seat> seats = new ArrayList<Seat>();
	private List<Card> tableCards = new ArrayList<Card>();
	private boolean isRoundStarted = false;
	private String dealerButton = "";
	private String holder = "";
	private int highestBet;
	private String highestBetOwner;
	private int pot;
	private int raiseCounter=0;
	private boolean gameOver = false;
	
	public Game() {
		for(int i=0;i<9;i++){
			seats.add(new Seat());
		}
	}
	
	public void startRound(){
		gameOver = false;
		tableCards.clear();
		deal();
		isRoundStarted = true;
	}
	
	public void resetStatuses(){
		for(int i=0; i<9; i++){
			if(seats.get(i).getPlayer() != null){
				if(seats.get(i).getPlayer().getCards()[0] != null){
					seats.get(i).getPlayer().setStatus("-");
				}
			}
		}
		setRaiseCounter(0);
	}
	
	public List<String> showdown() {
		List<String> cardList = new ArrayList<String>();
		for (int i = 0; i < 9; i++) {
			if(seats.get(i).getPlayer() != null){
				if(seats.get(i).getPlayer().getCards()[0] != null){
					cardList.add(seats.get(i).getPlayer().getCards()[0].toString());
					cardList.add(seats.get(i).getPlayer().getCards()[1].toString());
				}
			}
		}
		return cardList;
	}
	
	public void doAction(String action, int index, int money){
		if(seats.get(index).getPlayer().getSessionId().equals(holder)){
			
			if(action.equals("Raise")) {
				setRaiseCounter(getRaiseCounter() + 1);
				seats.get(index).getPlayer().setMoney(seats.get(index).getPlayer().getMoney()-((highestBet - seats.get(index).getPlayer().getCurrentBet())+money));
				pot += ((highestBet - seats.get(index).getPlayer().getCurrentBet())+money);
				highestBet += money;
				seats.get(index).getPlayer().setCurrentBet(highestBet);
				seats.get(index).getPlayer().setStatus(action+" to "+highestBet);
				highestBetOwner = seats.get(index).getPlayer().getSessionId();
			}
			if(action.equals("Call")){
				int value = highestBet - seats.get(index).getPlayer().getCurrentBet();
				seats.get(index).getPlayer().setMoney(seats.get(index).getPlayer().getMoney()-value);
				pot += value;
				seats.get(index).getPlayer().setCurrentBet(highestBet);
				seats.get(index).getPlayer().setStatus(action);
			}
			
			boolean checker = true;
			for(int i=0; i<9; i++){
				if(seats.get(i).getPlayer() != null){
					if(seats.get(i).getPlayer().getCards()[0] != null){
						if(seats.get(i).getPlayer().getCurrentBet()!=highestBet){
							checker = false;
						}
					}
				}
			}
			
			if(checker == true){
				switch(tableCards.size()){
					case 0:
						if(highestBetOwner == seats.get(index).getPlayer().getSessionId()){
							callFlop();
							resetStatuses();
						}
						break;
					case 3:
						if(highestBetOwner == seats.get(index).getPlayer().getSessionId()){
							betTurn();
							resetStatuses();
						}
						break;
					case 4:
						if(highestBetOwner == seats.get(index).getPlayer().getSessionId()){
							betRiver();
							resetStatuses();
						}
						break;
					default:
						setRaiseCounter(0);
						setGameOver(true);
						break;
				}
			}

			if(!isGameOver()){
				do{
					do{
						if(index == seats.size()-1) {
							index = -1;
						}
						index++;
					}while(seats.get(index).getPlayer()==null);
				}while(seats.get(index).getPlayer().getCards()[0]==null);
				
				resetIsTurns();
				holder = seats.get(index).getPlayer().getSessionId();
				seats.get(index).getPlayer().setTurn(true);
			}else{
				IPlayer player = getWinner().get(0);
				System.out.println(player.getName() + " wins!");
				player.setMoney(player.getMoney()+getPot());
				pot = 0;
				isRoundStarted = false;
				resetStatuses();
			}
		}
	}
	
	public void deal() {
		
		deck = new Deck();
		
		for (Seat seat : getSeats()) {
			if(seat.getPlayer() != null){

				seat.getPlayer().setCurrentBet(0);
				seat.getPlayer().getCards()[0] = deck.pop();
				seat.getPlayer().getCards()[1] = deck.pop();
				seat.getPlayer().setStatus("-");
				
			}
		}
		
		determineDealerButton();
		determineSmallBlind();
		determineBigBlind();
		determineHolder();
		
		checkPlayersRanking();
	}
	
	public void determineDealerButton() {
		
		for (Seat seat : getSeats()) {
			if(seat.getPlayer() != null){
				if(seat.getPlayer().getCards()[0] != null){
					seat.getPlayer().setAssignment("Other");
				}
			}
		}
		
		if(dealerButton==""){
			
			boolean flag = false;
			
			for (Seat seat : getSeats()) {
				if(seat.getPlayer() != null){
					if(seat.getPlayer().getCards()[0] != null){
						if(!flag){
							seat.getPlayer().setAssignment("Dealer Button");
							dealerButton = seat.getPlayer().getSessionId();
							flag = true;
						}
					}
				}
			}
			
		} else {
			
			int index = 0;
			
			for(int i = 0 ; i<9 ; i++){
				if(seats.get(i).getPlayer() != null){
					if(seats.get(i).getPlayer().getCards()[0] != null){
						if(seats.get(i).getPlayer().getSessionId().equals(dealerButton)){
							seats.get(i).getPlayer().setAssignment("Other");
							index = i;
						}
					}
				}
			}
			
			do{
				do{
					if(index == seats.size()-1) {
						index = -1;
					}
					index++;
				}while(seats.get(index).getPlayer()==null);
			}while(seats.get(index).getPlayer().getCards()[0]==null);
			
			seats.get(index).getPlayer().setAssignment("Dealer Button");
			dealerButton = seats.get(index).getPlayer().getSessionId();
		
		}
		
	}
	
	public void determineSmallBlind(){
		int index = 0;
		
		for(int i = 0 ; i<9 ; i++){
			if(seats.get(i).getPlayer() != null){
				if(seats.get(i).getPlayer().getCards()[0] != null){
					if(seats.get(i).getPlayer().getSessionId().equals(dealerButton)){
						index = i;
					}
				}
			}
		}
		
		do{
			do{
				if(index == seats.size()-1) {
					index = -1;
				}
				index++;
			}while(seats.get(index).getPlayer()==null);
		}while(seats.get(index).getPlayer().getCards()[0]==null);
		
		seats.get(index).getPlayer().setMoney(seats.get(index).getPlayer().getMoney() - 100);
		seats.get(index).getPlayer().setCurrentBet(100);
		pot += 100;
		seats.get(index).getPlayer().setAssignment("Small Blind");
	}
	
	public void determineBigBlind(){
		int index = 0;
		
		for(int i = 0 ; i<9 ; i++){
			if(seats.get(i).getPlayer() != null){
				if(seats.get(i).getPlayer().getCards()[0] != null){
					if(seats.get(i).getPlayer().getAssignment().equals("Small Blind")){
						index = i;
					}
				}
			}
		}
		
		do{
			do{
				if(index == seats.size()-1) {
					index = -1;
				}
				index++;
			}while(seats.get(index).getPlayer()==null);
		}while(seats.get(index).getPlayer().getCards()[0]==null);
		
		seats.get(index).getPlayer().setMoney(seats.get(index).getPlayer().getMoney() - 200);
		seats.get(index).getPlayer().setCurrentBet(200);
		pot+= 200;
		seats.get(index).getPlayer().setAssignment("Big Blind");
		highestBet = 200;
		highestBetOwner = seats.get(index).getPlayer().getSessionId();
	}

	public void determineHolder(){
		int index = 0;
		
		for(int i = 0 ; i<9 ; i++){
			if(seats.get(i).getPlayer() != null){
				if(seats.get(i).getPlayer().getCards()[0] != null){
					if(seats.get(i).getPlayer().getAssignment().equals("Big Blind")){
						index = i;
					}
				}
			}
		}
		
		do{
			do{
				if(index == seats.size()-1) {
					index = -1;
				}
				index++;
			}while(seats.get(index).getPlayer()==null);
		}while(seats.get(index).getPlayer().getCards()[0]==null);
		
		resetIsTurns();
		holder = seats.get(index).getPlayer().getSessionId();
		seats.get(index).getPlayer().setTurn(true);
	}
	
	public void resetIsTurns(){
		for(int i=0; i<9; i++){
			if(seats.get(i).getPlayer() != null){
				if(seats.get(i).getPlayer().getCards()[0] != null){
					seats.get(i).getPlayer().setTurn(false);
				}
			}
		}
	}
	
	public void callFlop() {
		deck.pop();
		tableCards.add(deck.pop());
		tableCards.add(deck.pop());
		tableCards.add(deck.pop());
		checkPlayersRanking();
	}

	public void betTurn() {
		deck.pop();
		tableCards.add(deck.pop());
		checkPlayersRanking();
	}

	public void betRiver() {
		deck.pop();
		tableCards.add(deck.pop());
		checkPlayersRanking();
	}
	
	public List<IPlayer> getWinner() {
		checkPlayersRanking();
		List<IPlayer> winnerList = new ArrayList<IPlayer>();
		IPlayer winner = getSeats().get(0).getPlayer();
		Integer winnerRank = RankingUtil.getRankingToInt(winner);
		winnerList.add(winner);
		for (int i = 1; i < getSeats().size(); i++) {
			if(getSeats().get(i).getPlayer() != null){
				if(getSeats().get(i).getPlayer().getCards()[0] != null) {
					IPlayer player = getSeats().get(i).getPlayer();
					Integer playerRank = RankingUtil.getRankingToInt(player);
					if (winnerRank == playerRank) {
						IPlayer highHandPlayer = checkHighSequence(winner, player);
						if (highHandPlayer == null) highHandPlayer = checkHighCardWinner(winner, player);
						if (highHandPlayer != null && !winner.equals(highHandPlayer)) {
							winner = highHandPlayer;
							winnerList.clear();
							winnerList.add(winner);
						} else if (highHandPlayer == null) {
							winnerList.add(winner);
						}
					} else if (winnerRank < playerRank) {
						winner = player;
						winnerList.clear();
						winnerList.add(winner);
					}
					winnerRank = RankingUtil.getRankingToInt(winner);
				}
			}
		}
		return winnerList;
	}

	@SuppressWarnings("unchecked")
	private IPlayer checkHighCardWinner(IPlayer player1, IPlayer player2) {
		IPlayer winner = compareHighCard(player1, player1.getHighCard(), player2, player2.getHighCard());
		if (winner == null) {
			Card player1Card = RankingUtil.getHighCard(player1, Collections.EMPTY_LIST);
			Card player2Card = RankingUtil.getHighCard(player2,	Collections.EMPTY_LIST);
			winner = compareHighCard(player1, player1Card, player2, player2Card);
			if (winner != null) {
				player1.setHighCard(player1Card);
				player2.setHighCard(player2Card);
			} else if (winner == null) {
				player1Card = getSecondHighCard(player1, player1Card);
				player2Card = getSecondHighCard(player2, player2Card);
				winner = compareHighCard(player1, player1Card, player2,
						player2Card);
				if (winner != null) {
					player1.setHighCard(player1Card);
					player2.setHighCard(player2Card);
				}
			}
		}
		return winner;
	}
	
	private IPlayer checkHighSequence(IPlayer player1, IPlayer player2) {
		Integer player1Rank = sumRankingList(player1);
		Integer player2Rank = sumRankingList(player2);
		if (player1Rank > player2Rank) return player1;
		else if (player1Rank < player2Rank) return player2;
		return null;
	}
	
	private void checkPlayersRanking() {
		for (Seat seat : getSeats()) {
			if(seat.getPlayer() != null){
				if(seat.getPlayer().getCards()[0] != null){
					RankingUtil.checkRanking(seat.getPlayer(), tableCards);
				}
			}
		}
	}
	
	private IPlayer compareHighCard(IPlayer player1, Card player1HighCard, IPlayer player2, Card player2HighCard) {
		if (player1HighCard.getRankToInt() > player2HighCard.getRankToInt()) return player1;
		else if (player1HighCard.getRankToInt() < player2HighCard.getRankToInt()) return player2;
		return null;
	}

	private Card getSecondHighCard(IPlayer player, Card card) {
		if (player.getCards()[0].equals(card)) {
			return player.getCards()[1];
		}
		return player.getCards()[0];
	}
	
	private Integer sumRankingList(IPlayer player) {
		Integer sum = 0;
		for (Card card : player.getRankingList()) sum += card.getRankToInt();
		return sum;
	}

	public List<Card> getTableCards() {
		return tableCards;
	}
	
	public List<Seat> getSeats() {
		return seats;
	}

	public void setSeats(List<Seat> seats) {
		this.seats = seats;
	}

	public boolean isRoundStarted() {
		return isRoundStarted;
	}

	public void setRoundStarted(boolean isRoundStarted) {
		this.isRoundStarted = isRoundStarted;
	}

	public String getHolder() {
		return holder;
	}

	public void setHolder(String holder) {
		this.holder = holder;
	}

	public String getDealerButton() {
		return dealerButton;
	}

	public void setDealerButton(String dealerButton) {
		this.dealerButton = dealerButton;
	}

	public int getPot() {
		return pot;
	}

	public void setPot(int pot) {
		this.pot = pot;
	}

	public String getHighestBetOwner() {
		return highestBetOwner;
	}

	public void setHighestBetOwner(String highestBetOwner) {
		this.highestBetOwner = highestBetOwner;
	}

	public int getRaiseCounter() {
		return raiseCounter;
	}

	public void setRaiseCounter(int raiseCounter) {
		this.raiseCounter = raiseCounter;
	}

	public boolean isGameOver() {
		return gameOver;
	}

	public void setGameOver(boolean gameOver) {
		this.gameOver = gameOver;
	}
}
